package com.game.business.pay.wxpay.controller;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.game.business.domain.PayParam;
import com.game.business.domain.TCzOrder;
import com.game.business.domain.TOrder;
import com.game.business.pay.wxpay.config.WxPayV3Bean;
import com.game.business.service.ITCzOrderService;
import com.game.business.service.ITOrderService;
import com.game.common.annotation.Anonymous;
import com.game.common.core.domain.AjaxResult;
import com.game.common.core.domain.entity.SysUser;
import com.game.common.utils.SecurityUtils;
import com.game.system.service.ISysUserService;
import com.google.gson.Gson;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.AuthTypeEnum;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
import com.ijpay.wxpay.model.v3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.*;


/**
 * 微信支付
 */
@Controller
@RequestMapping("/v3")
public class WxPayV3Controller  {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    private final static int OK = 200;

    @Resource
    WxPayV3Bean wxPayV3Bean;

    String serialNo;
    String platSerialNo;

    @Autowired
    private ITCzOrderService tOrderService;

    @Autowired
    private ISysUserService userService;



    private String getSerialNumber() {
        if (StrUtil.isEmpty(serialNo)) {
            // 获取证书序列号
            X509Certificate certificate = PayKit.getCertificate(wxPayV3Bean.getCertPath());
            if (null != certificate) {
                serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
                // 提前两天检查证书是否有效
                boolean isValid = PayKit.checkCertificateIsValid(certificate, wxPayV3Bean.getMchId(), -2);
                log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
            }
        }
        System.out.println("serialNo:" + serialNo);
        return serialNo;
    }


    /**
     * 小程序支付
     */
    @RequestMapping("/jsApiPay")
    @ResponseBody
    public AjaxResult jsApiPay(@RequestBody PayParam vo) {
        try {
            Snowflake snowflake = IdUtil.getSnowflake(1, 1);
            String orderNumber = String.valueOf(snowflake.nextId());
            TCzOrder order = new TCzOrder();
            order.setOrderNo(orderNumber);
            order.setUserId(SecurityUtils.getUserIdStr());
            order.setTitle("充值");
            order.setPrice(vo.getMoney());
            order.setJzbMoney(vo.getJzbMoney());
            order.setOrderStatus("1");
            order.setPayType("1");
            tOrderService.save(order);
            SysUser sysUser = userService.selectUserById(SecurityUtils.getUserId());
            String openId = sysUser.getOpenId();
            String outTradeNo = order.getOrderNo() + "_" + IdUtil.simpleUUID().substring(0, 10);
            order.setOutTradeNo(outTradeNo);
            tOrderService.updateById(order);
            BigDecimal orderprice = order.getPrice();
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setAppid(wxPayV3Bean.getMiniappId())
                    .setMchid(wxPayV3Bean.getMchId())
                    .setDescription("支付")
                    .setOut_trade_no(outTradeNo)
                    .setTime_expire(timeExpire)
                    .setAttach("微信系开发脚手架")
                    .setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
                    .setAmount(new Amount().setTotal(orderprice.multiply(new BigDecimal(100)).intValue()))
                    .setPayer(new Payer().setOpenid(openId));

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.POST,
                    WxDomainEnum.CHINA.toString(),
                    BasePayApiEnum.JS_API_PAY.toString(),
                    wxPayV3Bean.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayV3Bean.getKeyPath(),
                    JSONUtil.toJsonStr(unifiedOrderModel)
            );
            log.info("统一下单响应 {}", response);
            boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
            log.info("verifySignature: {}", verifySignature);
            if (response.getStatus() == OK && verifySignature) {
                String body = response.getBody();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                String prepayId = jsonObject.getStr("prepay_id");
                Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), prepayId, wxPayV3Bean.getKeyPath());
                log.info("唤起支付参数:{}", map);
                return  AjaxResult.success(JSONUtil.toJsonStr(map)) ;
            }
            return AjaxResult.success(response);
        } catch (Exception e) {
            log.error("系统异常", e);
            return  AjaxResult.error(e.getMessage());
        }
    }
    /**
     * app支付
     */
    @RequestMapping("/appPay")
    @ResponseBody
    public String appPay(@RequestBody PayParam vo) {
        try {
            Snowflake snowflake = IdUtil.getSnowflake(1, 1);
            String orderNumber = String.valueOf(snowflake.nextId());
            TCzOrder order = new TCzOrder();
            order.setOrderNo(orderNumber);
            order.setUserId(SecurityUtils.getUserIdStr());
            order.setTitle("充值");
            order.setPrice(vo.getMoney());
            order.setJzbMoney(vo.getJzbMoney());
            order.setOrderStatus("1");
            order.setPayType("2");
            tOrderService.save(order);
            SysUser sysUser = userService.selectUserById(SecurityUtils.getUserId());
            String openId = sysUser.getOpenId();
            String outTradeNo = order.getOrderNo() + "_" + IdUtil.simpleUUID().substring(0, 10);
            order.setOutTradeNo(outTradeNo);
            tOrderService.updateById(order);
            BigDecimal orderprice = order.getPrice();

            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setAppid(wxPayV3Bean.getAppId())
                    .setMchid(wxPayV3Bean.getMchId())
                    .setDescription("IJPay 让支付触手可及")
                    .setOut_trade_no(PayKit.generateStr())
                    .setTime_expire(timeExpire)
                    .setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
                    .setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
                    .setAmount(new Amount().setTotal(orderprice.multiply(new BigDecimal(100)).intValue()));

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.POST,
                    WxDomainEnum.CHINA.toString(),
                    BasePayApiEnum.APP_PAY.toString(),
                    wxPayV3Bean.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayV3Bean.getKeyPath(),
                    JSONUtil.toJsonStr(unifiedOrderModel),
                    AuthTypeEnum.RSA.getCode()
            );
            log.info("统一下单响应 {}", response);
            // 根据证书序列号查询对应的证书来验证签名结果
//			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
            // 微信支付公钥验证签名
            boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
            log.info("verifySignature: {}", verifySignature);
            if (response.getStatus() == OK && verifySignature) {
                String body = response.getBody();
                log.info("请求响应 {}", body);
                JSONObject jsonObject = JSONUtil.parseObj(body);
                String prepayId = jsonObject.getStr("prepay_id");
                Map<String, String> map = WxPayKit.appCreateSign(wxPayV3Bean.getAppId(), wxPayV3Bean.getMchId(), prepayId, wxPayV3Bean.getKeyPath());
                log.info("唤起支付参数:{}", map);
                return JSONUtil.toJsonStr(map);
            }
            return JSONUtil.toJsonStr(response);
        } catch (Exception e) {
            log.error("系统异常", e);
            return e.getMessage();
        }
    }
    @Anonymous
    @RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            log.info("支付通知密文 {}", result);
            String plainText = null;
            System.out.println("密码"+ wxPayV3Bean.getApiKey3());
            // 微信公钥验证签名并解密
//                plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
//                        wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
//            log.info("支付通知明文 {}", plainText);
             plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                    wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
            Gson gson = new Gson();
            if (StrUtil.isNotEmpty(plainText)) {
                HashMap hashMap = gson.fromJson(plainText, HashMap.class);
                String orderNo = (String) hashMap.get("out_trade_no");
                System.out.println(orderNo);
                String orderNo_real = orderNo.split("_")[0];
                // orderNo 是这种格式的    String outTradeNo = order.getOrderNo() + "_" + IdUtil.simpleUUID();
                // 根据orderNo 获取真实的orderNo
                tOrderService.processOrder(orderNo_real);
                System.out.println("微信notify_url 验证成功开始处理业务");
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            log.error("系统异常", e);
        }
    }






}
